Skip to main content

Video Downloads API

How to start, observe, and consume video downloads provided by DivaIOS.

Quick start​

  1. Create or adapt a model that conforms to DownloadableItem (use DownloadItemSummary for simple cases).
  2. Kick off a download with try await DownloadManager.shared.startDownload(item:).
  3. Observe progress and completions through DownloadManager.shared.events (Combine).
import DivaIOS

let item = DownloadItemSummary(
id: "my-video-001",
title: "Episode 1",
path: "https://example.com/path/to/master.m3u8",
images: ["poster": URL(string: "https://example.com/poster.jpg")!]
)

Task {
try await DownloadManager.shared.startDownload(item: item)
}

Core types​

  • DownloadableItem: id, title, path (HLS or MP4 URL), optional images. Provides serialize()/deserialize() for persistence. DownloadItemSummary is a ready-to-use implementation.
  • DownloadManager (DownloadManagerType): main entry point. Exposes startDownload, pauseDownload, resumeDownload, cancelDownload, getDownloadURL, isItemDownloaded, itemState, getItems(forStates:), plus bulk helpers (pauseAll, cancelAll, deleteAll, restart, cleanUp).
  • DownloadState: lifecycle (initialized, requested, pending, downloading, paused, completed, error, etc.). Use DownloadState.isQueued/inProgress to drive UI.
  • DownloadStateObserving: Combine publishers on DownloadManager (startedDownloadsPublisher, progressUpdatesPublisher, completedDownloadsPublisher, erroredDownloadsPublisher, stateChangesPublisher, unified events).
  • DownloadPolicy: controls account/profile scoping and URL shaping. Default is per-account (DownloadPolicyPerAccount); provide your own policy when you construct a custom DownloadManager.

Observe download lifecycle (Combine)​

final class DownloadsViewModel: ObservableObject {
@Published var rows: [Row] = []
private var cancellables = Set<AnyCancellable>()

init(service: DownloadManager = .shared) {
service.events
.receive(on: DispatchQueue.main)
.sink { [weak self] event in
guard let self else { return }
switch event {
case .started(let e), .progress(let e), .stateChanged(let e), .completed(let e):
self.upsert(e)
case .failed(let e, let error):
self.markFailed(e, reason: error.localizedDescription)
}
}
.store(in: &cancellables)
}
}

Starting downloads​

  • Direct URL: build a DownloadItemSummary with the stream URL in path and call startDownload(item:).
  • BO adapter convenience: if you already have an SWTestCaseCleanModel (as used in the test app), call startDownload(from:) to resolve entitlement and kick off the download.
  • Duplicate protection: startDownload throws DownloadError.alreadyQueued when the same item is already in the queue; DownloadError.setupInProgress guards concurrent setup for the same id.

Managing the queue​

  • Per-item: pauseDownload(itemId:), resumeDownload(itemId:), cancelDownload(itemId:).
  • Bulk: pauseAll(), cancelAll(), deleteAll() (completed/error/deleted/cancelling by default), restart() (rebuilds queued tasks after app relaunch), cleanUp() (removes orphaned records/files).
  • Queries: getItems(forStates:) returns current entities filtered by DownloadState.

Accessing the downloaded file​

  • Call await getDownloadURL(itemId:) to obtain the local URL once DownloadState.completed.
  • await isItemDownloaded(itemId:) is a convenience boolean check.
  • Files persist under Application Support/Downloads (see DownloadDataManager.baseURL); HLS temporary .movpkg paths are handled internally and returned as absolute URLs.

Background downloads​

  • Downloads run in a background URLSession. Bridge the system callback to the manager so the SDK can finish events:
// AppDelegate
func application(_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void) {
DownloadManager.shared.backgroundCompletionHandler = completionHandler
}
  • The provider notifies DownloadManager.shared.completeBackgroundEventsIfNeeded() when urlSessionDidFinishEvents fires; you only need to supply the completion handler above.

Policies, storage and limits​

  • Policy: pass a custom DownloadPolicy when initializing your own DownloadManager if downloads should be scoped by profile/account rules
  • Capacity/cellular prompts: DownloadManager.capacityWarningRequests and cellularWarningRequests are publishers you can use to present UI before proceeding when storage is tight or the connection switches to cellular.